// 定义调度优先级
const ImmediatePeriority = 1;  // 立即执行的优先级，优先级最高 [点击事件，输入框]
const UserBlockingPeriority = 2;  // 用户阻塞的优先级 [滚动、拖拽 ...]
const NormalPeriority = 3;  // 正常优先级 [render 列表 动画 网络请求]
const LowPeriority = 4;  // 低优先级 [数据上报，统计分析]
const IdlePeriority = 5;  // 最低优先级，可以被闲置的 [日志打印  console.log]

function getCurrentTime() {
    //performance.now() 是 JavaScript 中用于获取高精度时间戳的 API，属于 Web Performance API的一部分,特点如下：
    //高精度‌：可达微秒级（百万分之一秒），而 Date.now() 仅毫秒级（千分之一秒） ‌
    // 单调递增‌：时间戳持续增加，不受系统时间修改影响（即使调整系统时间，返回值仍保持连续）, Date.now() 可能因系统时间调整而变化 ‌
    // 相对时间起点‌：以页面加载或浏览器标签页首次打开时为参考点, Date.now() 以 UNIX 纪元（1970年1月1日）为基准 ‌
    // 防篡改‌：专门用于性能测量，浏览器会阻止恶意脚本修改其行为
    // 使用场景 性能分析‌：测量代码执行时间（如动画帧率、网络请求响应时间） | 精确同步动画帧
    // const start = performance.now();  
    // // 执行操作  
    // for(let i = 0; i < 1000000; i++) {console.log(i);}
    // const end = performance.now();  
    // console.log(`操作耗时: ${end - start} 毫秒`); 
    return performance.now();
}

// 定义调度任务,简单的调度器
class SimpleScheduler {
  constructor() {
    /**
     * 存储任务数据
     * {
     *  calback: () => {},
     *  priorityLevel: 1,
     *  expirationTime
     * }
     */
    this.taskQuue = [];    // 任务队列
    this.isPerformingWork = false;  // 是否正在执行任务
    const channel = new MessageChannel();
    this.port = channel.port2;  // 暂且用来发消息
    // channel.port1.onmessage = this.performWorkUntilDeadline;  // 监听消息
    channel.port1.onmessage = this.performWorkUntilDeadline.bind(this);  // 监听消息  下面要用到this去调用方法，这里要纠正this指向
  }
  
  /**
   * 
   * @param {优先级} priorityLevel 
   * @param {回调函数} callback 
   */
  scheduleCallback(priorityLevel, callback) {
    const curTime = getCurrentTime();
    let timeout;
    // 根据优先级设置超时时间
    switch (priorityLevel) {
      case ImmediatePeriority:
        timeout = 0;
        break;
      case UserBlockingPeriority:
        timeout = 250;
        break;
    //   case NormalPeriority:
    //     timeout = 5000;
    //     break;
      case LowPeriority:
        timeout = 10000;
        break;
      case IdlePeriority:
        timeout = 1073741823;   // 这个时间是 32位操作系统V8引擎所对应的最大时间
        break;
      default:
        timeout = 5000;
        break;
    }
    const task = {
      callback,
      priorityLevel,
      expirationTime: curTime + timeout
    }
   this.push(this.taskQuue, task);  // 将任务放入队列中

    //   this.port.postMessage(null);  // 触发调度  // 封装方法
    this.schedulePerformWorkUntilDeadline();
  }

  schedulePerformWorkUntilDeadline() {
    // this.port.postMessage(null);  // 触发调度
    // 加锁判断
    if (!this.isPerformingWork) {
        this.isPerformingWork = true;
        this.port.postMessage(null);  // 触发调度
    }
  }
  // 实现监听消息
  performWorkUntilDeadline() {
      console.log(this, 'this');
      // 这里要执行workloop方法，但是workloop方法需要this，所以这里要纠正this指向
      this.isPerformingWork = true;  // 加锁 判断
      this.workloop();
      this.isPerformingWork = false;  // 解锁
  }

  workloop() {
    // 执行任务
    let currTask = this.peek(this.taskQuue);
    while (currTask) {
      const { callback } = currTask;
      callback && callback();
      this.pop(this.taskQuue);
      currTask = this.peek(this.taskQuue);
    }
  }

  // 封装队列方法
  push(queue, task) {
    queue.push(task);  // 将任务放入队列中
    // 需要排下序
    queue.sort((a, b) => a.expirationTime - b.expirationTime);  
  }
  // 返回队列第一个
  peek(queue) {
    return queue[0];   // 每次取第一个
  }

  // 弹出
  pop(queue) {
    return queue.shift();   // ，每次删除第一个
  }
}

const scheduler = new SimpleScheduler();
// 调用时传优先级
scheduler.scheduleCallback(UserBlockingPeriority, () => {
  console.log('UserBlockingPeriority');
  console.log(2);
})
scheduler.scheduleCallback(ImmediatePeriority, () => {
  console.log('ImmediatePeriority');
  console.log(1);
})

